#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
视频处理核心模块
提供视频导入、帧预览、片段标记等核心功能
"""

import os
import ffmpeg
import cv2
import numpy as np
from typing import Optional, Tuple


class VideoProcessor:
    """
    视频处理器类
    
    负责视频文件的加载、信息提取和帧预览功能。使用ffmpeg-python库
    处理视频文件，提取视频流信息，并支持获取指定时间点的视频帧。
    
    该类是视频拼接工具的核心组件之一，为GUI界面提供视频数据支持。
    """

    def __init__(self):
        """
        初始化视频处理器
        
        创建视频处理器实例，初始化所有属性为默认值。
        """
        self.video_path: Optional[str] = None
        self.video_info: Optional[dict] = None
        self.cap = None

    def load_video(self, video_path: str) -> bool:
        """
        加载视频文件并提取信息
        
        使用ffmpeg-python库加载指定路径的视频文件，提取视频流的基本信息，
        包括时长、分辨率、编解码器、帧率等。成功加载后将信息存储在实例变量中。
        
        Args:
            video_path (str): 视频文件的完整路径，文件必须存在且可访问
            
        Returns:
            bool: 加载成功返回True，文件不存在、路径为空或加载过程中出错则返回False
            
        Note:
            - 支持常见视频格式（MP4, MOV, AVI, MKV等）
            - 自动检测视频流信息，包括分辨率、帧率、编解码器等
            - 帧率计算具有容错机制，无法解析时使用默认值30.0
            - 加载成功后会打印视频基本信息到控制台
            
        Example:
            >>> processor = VideoProcessor()
            >>> success = processor.load_video("/path/to/video.mp4")
            >>> if success:
            ...     print("视频加载成功")
            ... else:
            ...     print("视频加载失败")
        """
        if not video_path:
            print("错误：视频文件路径为空")
            return False
            
        if not os.path.exists(video_path):
            print(f"错误：视频文件不存在 {video_path}")
            return False

        try:
            # 使用ffmpeg获取视频信息
            probe = ffmpeg.probe(video_path)
            video_stream = next((stream for stream in probe['streams'] if stream['codec_type'] == 'video'), None)
            
            if video_stream is None:
                print("错误：未找到视频流")
                return False
                
            # 安全地获取帧率
            fps = 30.0  # 默认帧率
            if 'avg_frame_rate' in video_stream:
                try:
                    fps_fraction = video_stream['avg_frame_rate']
                    if isinstance(fps_fraction, str) and '/' in fps_fraction:
                        num, den = fps_fraction.split('/')
                        if float(den) != 0:
                            fps = float(num) / float(den)
                    else:
                        fps = float(fps_fraction)
                except:
                    pass  # 使用默认帧率
            
            self.video_path = video_path
            self.video_info = {
                'duration': float(probe['format'].get('duration', 0)),
                'width': int(video_stream.get('width', 0)),
                'height': int(video_stream.get('height', 0)),
                'codec': video_stream.get('codec_name', 'unknown'),
                'fps': fps,
                'bit_rate': int(probe['format'].get('bit_rate', 0)) if 'bit_rate' in probe['format'] else None
            }
            
            print(f"成功加载视频: {video_path}")
            print(f"视频信息: {self.video_info}")
            return True
            
        except ffmpeg.Error as e:
            print(f"FFmpeg错误: {e.stderr.decode() if e.stderr else str(e)}")
            return False
        except Exception as e:
            print(f"加载视频时出错: {e}")
            return False

    def get_video_info(self) -> Optional[dict]:
        """
        获取视频信息
        
        返回已加载视频的详细信息字典。字典包含视频的基本属性，
        如时长、分辨率、编解码器、帧率等。
        
        Returns:
            dict: 视频信息字典，如果未加载视频则返回None
            
        Note:
            - 该方法返回的是原始数据字典的引用，不是副本
            - 字典结构基于ffmpeg.probe()的输出
            - 主要包含以下键：duration, width, height, codec, fps, bit_rate
            - 如果视频未加载或加载失败，返回None
            
        Example:
            >>> processor = VideoProcessor()
            >>> processor.load_video("/path/to/video.mp4")
            >>> info = processor.get_video_info()
            >>> if info:
            ...     print(f"视频时长: {info['duration']}秒")
            ...     print(f"分辨率: {info['width']}x{info['height']}")
        """
        return self.video_info

    def get_frame_at_time(self, time_seconds: float) -> Optional[np.ndarray]:
        """
        获取指定时间点的视频帧
        
        使用ffmpeg提取视频中指定时间点的帧，并返回为numpy数组格式。
        返回的帧数据可以直接用于OpenCV处理。
        
        Args:
            time_seconds (float): 时间点（秒），必须为非负数
            
        Returns:
            np.ndarray: 帧图像数据（BGR格式），获取失败或未加载视频则返回None
            
        Note:
            - 返回的帧数据为BGR格式的numpy数组
            - 使用ffmpeg的ss参数精确定位时间点
            - 提取单帧图像并直接读取为数组
            - 临时文件会自动清理
            
        Example:
            >>> processor = VideoProcessor()
            >>> processor.load_video("/path/to/video.mp4")
            >>> frame = processor.get_frame_at_time(10.5)
            >>> if frame is not None:
            ...     print(f"帧数据形状: {frame.shape}")
            ... else:
            ...     print("获取帧数据失败")
        """
        if not self.video_path or not self.video_info:
            return None
            
        try:
            # 创建临时帧文件
            output_path = f"/tmp/frame_{time_seconds}.png"
            
            (
                ffmpeg
                .input(self.video_path, ss=time_seconds)
                .output(output_path, vframes=1)
                .overwrite_output()
                .run(capture_stdout=True, capture_stderr=True)
            )
            
            # 读取图像文件为numpy数组
            frame = cv2.imread(output_path)
            
            # 清理临时文件
            try:
                os.remove(output_path)
            except:
                pass  # 忽略清理错误
            
            return frame
        except ffmpeg.Error as e:
            print(f"FFmpeg获取视频帧时出错: {e.stderr.decode() if e.stderr else str(e)}")
            return None
        except Exception as e:
            print(f"获取视频帧时出错: {e}")
            return None

    def get_video_duration(self) -> float:
        """
        获取视频总时长
        
        Returns:
            float: 视频总时长（秒）
        """
        if self.video_info:
            return self.video_info.get('duration', 0.0)
        return 0.0


if __name__ == "__main__":
    # 测试代码
    processor = VideoProcessor()
    # 示例：processor.load_video("test.mp4")